package sc;

/**
 *  Catmull-Rom Spline
 *  Stephen Carmody
 *  J2SE 5
 */

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.image.BufferStrategy;

import javax.swing.JFrame;

import sc.math.CatmullRomCurve;
import sc.math.Spline2D;

public final class catmullromsplines extends JFrame implements MouseListener,
        MouseMotionListener {

    private static final long serialVersionUID = 1L;
    private static Spline2D spline;
    private static int selected;
    private static boolean mousePressed;
    private static boolean mouseDragged;
    private static Point mouse;

    /** Constructs an instance of beziercurves */
    public catmullromsplines(int width, int height) {
        setSize(width, height);
        setTitle("Catmull-Rom Splines");
        setResizable(false);
        addMouseListener(this);
        addMouseMotionListener(this);
        addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent e) {
                System.exit(0);
            }
        });
        setVisible(true);

        spline = new Spline2D(new CatmullRomCurve());
        selected = -1;
        mouse = new Point();

        // start with one randomly generated curve
        for (int i = 0; i < 2; i++) {
            int x = 40 + (int) (Math.random() * (width - 80));
            int y = 40 + (int) (Math.random() * (height - 80));
            spline.points.add(new Point(x, y));
            spline.points.add(new Point(x + (int) (Math.random() * 40) - 20, y
                    + (int) (Math.random() * 40) - 20));
        }
        spline.updateIntervals();
    }

    /** Listens for mouse button pressed events */
    public void mousePressed(MouseEvent e) {
        mousePressed = true;
    }

    /** Listens for mouse button released events */
    public void mouseReleased(MouseEvent e) {
        mousePressed = false;
        selected = -1;
    }

    /** Listens for mouse move events */
    public void mouseMoved(MouseEvent e) {
        mouse.x = e.getX();
        mouse.y = e.getY();
    }

    /** Listens for mouse drag events */
    public void mouseDragged(MouseEvent e) {
        mouseDragged = true;
        mouse.x = e.getX();
        mouse.y = e.getY();
    }

    public void mouseClicked(MouseEvent e) {
    }

    public void mouseEntered(MouseEvent e) {
    }

    public void mouseExited(MouseEvent e) {
    }

    public static void main(String[] args) {
        catmullromsplines b = new catmullromsplines(640, 480);

        // framerate info buffer
        long[] framerate = new long[4];

        // create a double-buffering buffer stragey
        b.createBufferStrategy(2);
        BufferStrategy s = b.getBufferStrategy();
        Graphics2D g;

        while (b.isVisible()) {
            // get the off screen graphics context and clear it
            g = (Graphics2D) s.getDrawGraphics();
            g.setColor(new Color(0xffffff));
            g.fillRect(0, 0, b.getWidth(), b.getHeight());
            g.setColor(new Color(0x000000));

            // draw the spline
            Point prev = null;
            for (Point next : spline.intervals) {
                if (prev != null)
                    g.drawLine(prev.x, prev.y, next.x, next.y);
                prev = next;
            }

            int i = 0;
            for (Point p : spline.points) {
                g.drawString(i + "", p.x, p.y);
                if (mousePressed) {
                    int x = mouse.x - p.x;
                    int y = mouse.y - p.y;
                    if (x >= 0 && x <= 9 && y <= 0 && y >= -9)
                        selected = i;
                }
                i++;
            }

            // When mouse has been dragged and a point is selected
            if (mouseDragged && selected != -1) {
                Point p = spline.points.get(selected);
                p.x = mouse.x;
                p.y = mouse.y;
                spline.updateIntervals();
            }
            
            // Else when mouse pressed over unoccupied space
            else if (mousePressed && selected == -1) {
                spline.points.add(new Point(mouse.x, mouse.y));
                spline.updateIntervals();
            }

            // calculate framerate
            framerate[1]++;
            framerate[3] = System.currentTimeMillis();
            if ((framerate[3] - framerate[2]) > 1000) {
                framerate[0] = framerate[1];
                framerate[1] = 0;
                framerate[2] = framerate[3];
            }
            g.drawString(framerate[0] + " fps", 10, 40);

            // swap the buffers
            s.show();
        }
    }

}
